package net.vkits.anjiamiao.domain.service;

import net.vkits.anjiamiao.domain.event.*;
import net.vkits.anjiamiao.domain.model.*;
import net.vkits.anjiamiao.domain.repository.*;
import net.vkits.common.exceptions.NoSuchUserException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.HashSet;
import java.util.Set;

/**
 * Created by ethan-liu on 2016/12/27.
 */
@Service
public class OrderService {
    private static final Logger logger = LoggerFactory.getLogger(OrderService.class);

    @Resource
    private CustomerRepository customerRepository;
    @Resource
    private ContractRepository contractRepository;
    @Resource
    private OrderRepository orderRepository;
    @Resource
    private DeviceRepository deviceRepository;
    @Resource
    private MessageRepository messageRepository;
    @Resource
    private ApplicationContext applicationContext;

    public Order createOrder(OriginalOrder originalOrder, String cellPhoneNum){
        Customer customer = customerRepository.findByCellPhoneNumAndDeletedFalse(cellPhoneNum).orElseThrow(NoSuchUserException::new);
        if (customer.getIsBlock()) {
            logger.info("get a Block user");
        }
        if (customer.getIsVIP()) {
            logger.info("get a VIP user");
        }
        Contract contract = contractRepository.findByUserPhoneAndDeletedFalse(cellPhoneNum).orElseThrow(NoSuchUserException::new);
        BigDecimal amount = BigDecimal.valueOf(Double.valueOf(originalOrder.getAmount()));
        BigDecimal serviceFee = BigDecimal.valueOf(Double.valueOf(originalOrder.getServiceFee()));
        BigDecimal rentAmount = amount.subtract(serviceFee);
        Order order = new Order(originalOrder,
                customer.getName(),
                rentAmount,
                cellPhoneNum,
                contract.getLandlord(),
                contract.getAccount(),
                contract.getBank());
        return orderRepository.save(order);
    }

    public void changeStatus(String id, String status) {
        Order order = orderRepository.findByIdAndDeletedFalse(id);
        Set<Device> devices = deviceRepository.findByCellphone(order.getCellPhoneNum());
        Set<String> umDeviceTokens = new HashSet<>();
        devices.forEach(device -> umDeviceTokens.add(device.getUmDeviceToken()));
        TradeStatus tradeStatus = TradeStatus.valueOf(status);
        Message message = new Message();
        message.setStatus(tradeStatus);
        message.setAccount(order.getAccount());
        message.setRentAmount(BigDecimal.valueOf(Double.parseDouble(order.getOriginalOrder().getAmount())));
        message.setTitle("房租到账进度通知");
        message.setSender("system");
        message.setStartDate(order.getCreateTime().toLocalDate().toString());
        message.setUmDeviceTokens(umDeviceTokens);
        message.setOrderId(id);
        message.setCellPhoneNum(order.getCellPhoneNum());
        message.setBank(order.getBank());
        switch (tradeStatus) {
            // 支付中
            case Process: {
                applicationContext.publishEvent(new PayEvent(order.getRentAmount(), order.getBank(), order.getAccount()));
                break;
            }
            // 处理中
            case Paid: {
                message.setMidDate(LocalDate.now().toString());
                message.setEndDate(LocalDate.now().plusDays(1L).toString());
                applicationContext.publishEvent(new PayEvent(order.getRentAmount(), order.getBank(), order.getAccount()));
                break;
            }
            // 转账成功
            case TransferSuccess: {
                message.setMidDate(LocalDate.now().toString());
                message.setEndDate(LocalDate.now().toString());
                message.setRentAmount(order.getRentAmount());
                // event
                TransferSuccessEvent event = new TransferSuccessEvent();
                event.setBank(order.getBank());
                event.setRentAmount(order.getRentAmount());
                event.setCellPhoneNum(order.getCellPhoneNum());
                event.setAccount(order.getAccount());
                event.setCustomerName(order.getCustomerName());
                event.setHasDeposit(order.getOriginalOrder().getHasDeposit());
                event.setHasFee(order.getOriginalOrder().getHasFee());
                event.setLandlord(order.getLandlord());
                event.setNotifyLandlord(order.getOriginalOrder().getNotifyLandlord());
                applicationContext.publishEvent(event);
                break;
            }
            case RiskTrade: {
                message.setMidDate(LocalDate.now().toString());
                message.setEndDate(LocalDate.now().plusDays(5L).toString());
                applicationContext.publishEvent(new RiskWarningEvent(order.getCellPhoneNum()));
                break;
            }
            case TransferFailed: {
                message.setMidDate(LocalDate.now().toString());
                message.setEndDate(LocalDate.now().plusDays(5L).toString());
                TransferFailureEvent event = new TransferFailureEvent();
                event.setAccount(order.getAccount());
                event.setBank(order.getBank());
                event.setCellPhoneNum(order.getCellPhoneNum());
                event.setRentAmount(BigDecimal.valueOf(Double.parseDouble(order.getOriginalOrder().getAmount())));
                applicationContext.publishEvent(event);
                break;
            }
            case TransferFailedRefund: {
                message.setMidDate(LocalDate.now().toString());
                message.setEndDate(LocalDate.now().toString());
                RefundEvent event = new RefundEvent();
                event.setCellPhoneNum(order.getCellPhoneNum());
                event.setRentAmount(order.getOriginalOrder().getAmount());
                applicationContext.publishEvent(event);
                break;
            }
            case RiskTradeRefund: {
                message.setMidDate(LocalDate.now().toString());
                message.setEndDate(LocalDate.now().toString());
                RefundEvent event = new RefundEvent();
                event.setCellPhoneNum(order.getCellPhoneNum());
                event.setRentAmount(order.getOriginalOrder().getAmount());
                applicationContext.publishEvent(event);
                break;
            }
            default:
                break;
        }
        order.setStatus(tradeStatus);
        if (!tradeStatus.equals(TradeStatus.Process)) {
            Message m = messageRepository.save(message);
            applicationContext.publishEvent(m);
        }
        orderRepository.save(order);
    }
}
